import Taro from "@tarojs/taro";
import { LivePlayerProps } from "@tarojs/components/types/LivePlayer";
import { LivePusherProps } from "@tarojs/components/types/LivePusher";
import { BaseEventOrig } from "@tarojs/components";
import {
  tap,
  switchMap,
  filter,
  catchError,
  mergeMap,
  map
} from "rxjs/operators";
import { arrayAdd, arrayRemove, arrayUpdate } from "@datorama/akita";
import { EMPTY, firstValueFrom, of } from "rxjs";

import { RoomQuery, RoomStore, makeStore } from "@/state/room/store";
import { AuthQuery, makeStore as makeAuthStore } from "@/state/auth/store";
import { MessageQuery, makeStore as makeMsgStore } from "@/state/message/store";

import {
  DeleteFileReq,
  EditRoomParams,
  EtcDataReq,
  fileSynReq,
  fileTransCodeReq,
  RoomStatReq,
  SignInContentReq,
  SignInSettingReq,
  UploadFileReq
} from "@/models/request/roomReq";
import roomService from "@/services/roomService";
import {
  COMPONENT_OPERATION,
  LIVE_MODE,
  LIVE_OPERATION,
  LIVE_TYPE,
  MUTE_STATUS,
  ROOM_ROLE,
  ROOM_STATUS
} from "@/constants/room";
import { CMD } from "@/constants/message";
import { Assistant, File, Anchor, BeautyLevel, HDLevel, Room } from "@/models/LiveRoom";
import { GetInvitesRsp, GetRoomRsp } from "@/models/response/roomRsp";
import messageService from "@/services/messageService";
import { isObjEmpty } from "@/utils";

// 类似于仓储Repository， 但也是门面设计模式，引入store和api请求等相关实现，对页面组件隐藏复杂实现，也是前端中的view model
export class RoomFacade {
  [x: string]: any;
  constructor(private store: RoomStore, private query: RoomQuery, private authQuery: AuthQuery, private msgQuery: MessageQuery) {
    //箭头函数不需要bind作用域
    // this.getRoomInfo = this.getRoomInfo.bind(this);
  }

  //FIXME  结尾为$的变量为需要绑定到页面的数据，注意：没有$美金符号的变量只是值传递，属于快照，不是最新的值，需要最新的值就使用this.query.roomId这样的查询方法
  readonly ui_muted$ = this.query.ui_muted$;
  readonly ui_debug$ = this.query.ui_debug$;
  readonly ui_isFront$ = this.query.ui_isFront$;
  readonly ui_mode$ = this.query.ui_mode$;
  readonly ui_beauty$ = this.query.ui_beauty$;
  readonly ui_operation$ = this.query.ui_operation$;
  readonly videoProgress$ = this.query.ui_progress$;
  readonly videoEnded$ = this.query.ui_videoEnded$;

  readonly roomRole$ = this.query.roomRole$;
  readonly roomName$ = this.query.roomName$;
  readonly roomId$ = this.query.roomId$;
  readonly orgId$ = this.query.orgId$;
  readonly picUrl$ = this.query.picUrl$;
  readonly orgName$ = this.query.orgName$;
  readonly orgLogo$ = this.query.orgLogo$;
  readonly tips$ = this.query.tips$;
  readonly status$ = this.query.status$;

  readonly signInOptions$ = this.query.signInOptions$;

  readonly direction$ = this.query.direction$;
  readonly inviteStatus$ = this.query.inviteStatus$;
  readonly muteStatus$ = this.query.muteStatus$;
  readonly passwd$ = this.query.passwd$;
  readonly type$ = this.query.type$;
  readonly ownerId$ = this.query.ownerId$;
  readonly ownerName$ = this.query.ownerName$;
  readonly files$ = this.query.files$;
  readonly anchorId$ = this.query.anchorId$;
  readonly anchorName$ = this.query.anchorName$;
  readonly assistants$ = this.query.assistants$;
  readonly preLoadVideo$ = this.query.preLoadVideo$;
  readonly pauseVideo$ = this.query.pauseVideo$;
  readonly description$ = this.query.description$;
  readonly startTime$ = this.query.startTime$;
  readonly endTime$ = this.query.endTime$;
  readonly duration$ = this.query.duration$;
  readonly visits$ = this.query.visits$;
  readonly shares$ = this.query.shares$;
  readonly likes$ = this.query.likes$;
  readonly liveStreams$ = this.query.liveStreams$;
  readonly linkStreams$ = this.query.linkStreams$;
  readonly notifyMsg$ = this.msgQuery.notifyMsg$;
  readonly forceSignIn$ = this.query.forceSignIn$;
  readonly allowShare$ = this.query.allowShare$;
  readonly ownerLogo$ = this.query.ownerLogo$;
  readonly anchorLogo$ = this.query.anchorLogo$;
  readonly audioStatus$ = this.query.audioStatus$;
  readonly audienceToast$ = this.query.audienceToast$;

  //获取当前room对象，用于直播间编辑
  getRoomInfo = () => {
    const room = {} as Room;
    room.roomName = this.query.roomName;
    room.roomId = this.query.roomId;
    room.description = this.query.description;
    room.ownerName = this.query.ownerName;
    room.startTime = this.query.startTime;
    room.endTime = this.query.endTime;
    room.picUrl = this.query.picUrl;
    room.preLoadVideo = this.query.preLoadVideo;
    room.pauseVideo = this.query.preLoadVideo;
    room.direction = this.query.direction;

    return room;
  }

  clearUiOperate = () => {
    this.store.update(state => {
      //清理操作，以免页面onShow时重复触发操作
      state.ui.operation = "";
    });
  }

  //更新播放视频进度
  updateProgress = (progress: number) => {
    this.store.update(state => {
      state.ui.progress = progress;
    });
  }

  //更新播放视频状态是否结束
  updateVideoEnd = (progressStatus: boolean) => {
    this.store.update(state => {
      state.ui.videoEnded = progressStatus;
    });
  }

  //BUG 恢复直播或者拉流，需要解决onhie onshow 自动推流问题
  resume = () => {
    console.log("resume当前房间状态: ", this.query.status);

    if (this.query.status === ROOM_STATUS.PAUSED && (this.query.roomRole === ROOM_ROLE.OWNER_ANCHOR || this.query.roomRole === ROOM_ROLE.ANCHOR)) {
      //自动恢复推拉流
      this.uiOperate(LIVE_OPERATION.RESUME);
    }
  }

  //暂停直播或者拉流
  pause = () => {
    console.log("pause当前房间状态: ", this.query.status);

    if (this.query.status === ROOM_STATUS.STARTED && (this.query.roomRole === ROOM_ROLE.OWNER_ANCHOR || this.query.roomRole === ROOM_ROLE.ANCHOR)) {
      //自动暂停推拉流
      this.uiOperate(LIVE_OPERATION.PAUSE);
    }
  }

  //页面和组件公用的UI操作逻辑，主要由操作层用户点击触发
  uiOperate = (type: string, value?: string) => {
    switch (type) {
      //以下向组件层传递非摄像头类操作参数
      case COMPONENT_OPERATION.CHANGE_MODE: {
        //确保传值合法
        if ([LIVE_MODE.FHD, LIVE_MODE.HD, LIVE_MODE.RTC, LIVE_MODE.SD].includes(value || 'HD')) {
          const mode = value as HDLevel;
          this.store.update(state => {
            state.ui.mode = mode;
          });
        }
        break;
      }
      case COMPONENT_OPERATION.TOGGLE_CAMERA: {
        const flag = !this.query.ui_isFront;
        this.store.update(state => {
          state.ui.isFront = flag;
          state.ui.operation = type;
        });
        break;
      }
      case COMPONENT_OPERATION.TOGGLE_DEBUG: {
        const flag = this.query.ui_debug;
        this.store.update(state => {
          state.ui.debug = !flag;
        });
        break;
      }
      case COMPONENT_OPERATION.TOGGLE_MUTE: {
        const flag = this.query.ui_muted;
        this.store.update(state => {
          state.ui.muted = !flag;
        });
        break;
      }
      case COMPONENT_OPERATION.CHANGE_BEAUTY: {
        //设定值范围
        const beauty = parseInt(value || "5") as BeautyLevel;
        this.store.update(state => {
          state.ui.beauty = beauty;
        });
        break;
      }
      case COMPONENT_OPERATION.PLAY_VIDEO:
      case LIVE_OPERATION.START:
      case LIVE_OPERATION.STOP:
      case LIVE_OPERATION.PAUSE:
      case LIVE_OPERATION.RESUME: {
        this.store.update(state => {
          state.ui.operation = type;
        });

        break;
      }
      default: {
        //除了上面的UI操作之外的操作
        break;
      }
    }
  }

  //房间角色身份查询或更新
  judgeRole = () => {
    const loginStatus = this.authQuery.loginStatus;

    const userId = this.authQuery.userId;
    const ownerId = this.query.ownerId;
    const anchorId = this.query.anchorId;
    const assistants = this.query.assistants;
    const linkStreams = this.query.linkStreams;

    //判断当前用户是否在助手列表
    const isAssistant = assistants.some(e => {
      return userId === e.userId;
    });

    //判断当前用户是否在推流列表
    const isLinkAnchor = linkStreams.some(e => {
      return userId === e.owner && ownerId !== e.owner && e.status !== ROOM_STATUS.ENDED;
    });
    //不登录的默认就是观众
    let roomRole = ROOM_ROLE.AUDIENCE;

    if (loginStatus && userId) {
      //按情况总共5种身份
      if (userId !== ownerId) {
        if (userId !== anchorId) {
          if (!isAssistant) {
            roomRole = ROOM_ROLE.AUDIENCE; //观众。默认没有userId的都是观众
          } else {
            roomRole = ROOM_ROLE.ASSISTANT; //助理
          }

          if (isLinkAnchor) roomRole = ROOM_ROLE.LINK_ANCHOR; //连麦主播
        } else {
          roomRole = ROOM_ROLE.ANCHOR; //接收了开播权的主播
        }
      } else {
        if (!anchorId) {
          roomRole = ROOM_ROLE.OWNER_ANCHOR; //没有转移开播权的主播
        } else {
          roomRole = ROOM_ROLE.OWNER_ASSISTANT; //转移了开播权的主播
        }
      }
    }
    console.log('调用judgeRole', roomRole);

    this.store.update(state => {
      state.roomRole = roomRole;
    })
  }

  //监听主播推流组件的事件
  onMainPush = (e: BaseEventOrig<LivePusherProps.onStateChangeEventDetail>) => {
    // console.log('语音直播没有开始的原因', e.detail);

    switch (e.detail.code) {
      case 1002:
      case 2027:
        {
          //这里在小程序各种操作下主动触发观众端拉流
          console.log("状态码1002, 已经与服务器握手完毕,开始推流");
          //群发开始直播通知  
          //firstValueFrom(this.sendGroupNotifyMsg(this.query.roomId, CMD.OPERATE_CAMERA, ROOM_STATUS.STARTED.toString()));
          break;
        }
      case -1307:
        {
          //网络原因推流失败
          Taro.showToast({
            title: '状态码-1307, 网络断连，且经多次重连抢救无效，更多重试请自行重启推流',
            icon: 'none',
            duration: 5000
          })
          this.uiOperate(LIVE_OPERATION.PAUSE);
          console.error("状态码-1307, 网络断连，且经多次重连抢救无效，更多重试请自行重启推流")
          //群发暂停直播通知
          firstValueFrom(this.sendGroupNotifyMsg(this.query.roomId, CMD.OPERATE_CAMERA, ROOM_STATUS.PAUSED.toString()));
          break;
        }
      default:
        break;
    }
  }

  // 监听网络状态
  onMainStash = (e: BaseEventOrig<LivePusherProps.onNetstatusEventDetail>) => {
    console.log('监听网络状态', e, e.detail.info.audioBitrate);
    if (e.detail.info.audioBitrate) {
      console.log('当前有声音,audioStatus为true', e.detail.info.audioBitrate);

      this.store.update(state => {
        state.audioStatus = true
      })
    } else {
      this.store.update(state => {
        state.audioStatus = false
      })
    }
  }

  //监听主播推流组件的错误事件
  onMainError = (e: any) => {
    console.log("onMainError事件", e.detail);
  }

  //监听观众拉流组件的事件
  onMainPlayState = (e: BaseEventOrig<LivePlayerProps.onStateChangeEventDetail>) => {
    // console.log('观众拉流状态码, ', e.detail);
    // console.log('观众拉流地址, ', this.query.liveStreams[0].flvPlayUrl);

    switch (e.detail.code) {
      case -2301:
        {
          if (this.query.status === ROOM_STATUS.STARTED || this.query.status === ROOM_STATUS.RESUME) {
            console.log("状态码-2301, 网络断连，且经多次重连抢救无效，更多重试请自行重启播放");
            this.store.update(state => {
              state.status = ROOM_STATUS.PAUSED;
            })
            // 主播断连时小主播也退出
            if (this.query.roomRole === ROOM_ROLE.LINK_ANCHOR) this.quitLink(this.authQuery.userId);
          }
        }
        break;
      default:
        break;
    }
  }

  //监听连麦主播推流组件的事件
  onLinkPush = (e: BaseEventOrig<LivePusherProps.onStateChangeEventDetail>) => {
    switch (e.detail.code) {
      case 1002:
        {
          //这里在小程序各种操作下主动触发观众端拉流
          console.log("状态码1002, 已经与服务器握手完毕,开始连麦推流");
          //群发开始直播通知  
          firstValueFrom(messageService.updateLinkMicSvc(this.query.roomId, this.authQuery.userId, ROOM_STATUS.STARTED));
          break;
        }
      case -1307:
        {
          console.log("状态码-1307, 网络断连，且经多次重连抢救无效，更多重试请自行重启推流");
          break;
        }
      default:
        break;
    }
  }

  // 连麦拉流事件
  onLinkPlay = (e: BaseEventOrig<LivePusherProps.onStateChangeEventDetail>) => {
    switch (e.detail.code) {
      case 2002:
        {
          //这里在小程序各种操作下主动触发观众端拉流
          console.log("状态码2002, 已经与服务器握手完毕,开始拉流");
          break;
        }
      default:
        break;
    }
  }

  //监听连麦主播推流组件的错误事件
  onLinkError = (e: any) => {
    console.log("onLinkError事件", e, e.detail.code);
  }

  //主动退出连麦
  quitLink = (userId: string) => {
    //TODO 写退出连麦逻辑
    //this.judgeRole();
    return messageService.updateLinkMicSvc(this.query.roomId, userId, ROOM_STATUS.ENDED);

  }

  //踢出连麦
  kickoutJoinAnchor = (userId: string) => {
    console.log('点击了踢出连麦', userId);

    // 更新小主播状态
    return messageService.updateLinkMicSvc(this.query.roomId, userId, ROOM_STATUS.ENDED);
  }

  // 更新连麦人数
  audienceListToast = (toast: number) => {
    this.store.update(state => {
      state.audienceToast = toast
    })
  }

  //TODO 进入房间，需要把过多的网络查询进行合并
  enterRoom = (roomId: string) => {
    //return forkJoin([this.getRoom(roomId), this.getLiveStreams(roomId), this.getFiles(roomId)])
    return this.getRoom(roomId)
      .pipe(
        //需要登录的才执行后续步骤
        filter(() => this.authQuery.loginStatus),
        switchMap(roomData => {
          //主播进房或者观众进房的操作
          if (this.authQuery.userId === this.query.ownerId || this.authQuery.userId === this.query.anchorId) {
            //FIXME 解决之前的房间未暂停问题，防止进入房间或者onHide, onShow自动直播的问题
            if (roomData.status === ROOM_STATUS.STARTED && roomData.type !== LIVE_TYPE.TEXT) {
              this.store.update(state => {
                state.status = ROOM_STATUS.PAUSED;
              })
            }
            return this.addAnchor()
              .pipe(
                tap(this.judgeRole),
                mergeMap(() => EMPTY)
              )
          } else {
            return this.addAudience()
              .pipe(
                map(() => roomData)
              )
          }
        }),
        catchError(() => {
          //发生异常也继续执行，下面的角色判断不能中断，发生异常后默认作为观众进入房间
          return of({} as GetRoomRsp);
        }),
        //BUG，必须放这里，放其他api请求之前会导致API请求出错
        //tap(this.judgeRole)
      )
  }

  addAnchor = () => {
    return roomService.addAnchorSvc(this.query.roomId);
  }

  addAudience = () => {
    return roomService.addAudienceSvc(this.query.roomId);
  }

  //把主播自己从房间移除
  delAnchor = (roomId: string) => {
    return roomService.delAnchorSvc(roomId);
  }

  //把观众自己从房间移除
  delAudience = (roomId: string) => {
    return roomService.delAudienceSvc(roomId);
  }

  //创建人移除邀请的主播
  delInviteAnchor = (roomId: string) => {
    return roomService.delInviteAnchorSvc(roomId)
      .pipe(
        tap(res => {
          console.log("移除邀请主播成功: ", res)
          this.store.update(state => {
            state.anchorId = "";
            state.anchorName = "";
          });
        })
      )
  }

  //创建人移除助理
  delAssistant = (roomId: string, userId: string) => {
    return roomService.delAssistantSvc(roomId, userId)
      .pipe(
        tap(res => {
          const assistant = this.query.assistants.find(item => item.userId === userId);
          if (assistant) {
            this.store.update(state => ({
              assistants: arrayRemove(state.assistants, userId, "userId")
            }))
          }
        })
      )
  }

  // 离开房间
  leaveRoom = (roomId: string) => {
    if (this.authQuery.loginStatus !== false) {
      //退出房间
      if (this.query.roomRole == ROOM_ROLE.OWNER_ANCHOR || this.query.roomRole == ROOM_ROLE.ANCHOR) {
        if (this.query.status === ROOM_STATUS.STARTED) {
          //主播身份则暂停直播
          firstValueFrom(this.operateCamera(LIVE_OPERATION.PAUSE));
        }
        firstValueFrom(this.delAnchor(roomId));
      } else {
        firstValueFrom(this.delAudience(roomId));
      }
    }
  }

  // 进入新房间则重置房间状态
  resetRoomStore = (newRoomId?: string) => {
    //不传newRoomId就强制清理数据
    if (newRoomId) {
      if (!this.query.roomId || this.query.roomId === newRoomId) {
        return;
      }
    }
    this.store.reset();
  }

  //获取主播流并写入store
  getLiveStreams = (roomId: string) => {
    return roomService.getLiveStreamsSvc(roomId)
      .pipe(
        tap(streamsRes => {
          this.store.update(state => {
            state.liveStreams = streamsRes;
          });
        })
      );
  }

  //获取连麦流并写入store
  getLinkStreams = (roomId: string) => {
    return roomService.getLinkStreamsSvc(roomId)
      .pipe(
        tap(streamsRes => {
          this.store.update(state => {
            state.linkStreams = streamsRes;
          })
        })
      )
  }

  //获取房间文件列表
  getFiles = (roomId: string) => {
    return roomService.getFilesSvc(roomId)
      .pipe(
        tap(filesRes => {
          if (filesRes.length > 0) {
            this.store.update(state => {
              state.files = filesRes;
            })
          }
        })
      )
  }

  //上传房间文件
  uploadFile = (uploadFileReq: UploadFileReq) => {
    return roomService.uploadFileSvc(uploadFileReq.roomId, uploadFileReq.fileName, uploadFileReq.fileUrl)
      .pipe(
        tap((file) => {
          this.store.update(({ files }) => ({
            files: arrayAdd(files, file)
          }));
        }),
        switchMap((file) => this.sendGroupNotifyMsg(this.query.roomId, CMD.UPLOAD_FILES, JSON.stringify({ file })))
      )
  }

  //删除房间文件
  deleteFile = (deleteFileReq: DeleteFileReq) => {
    return roomService.deleteFileSvc(deleteFileReq.roomId, deleteFileReq.fileId)
      .pipe(
        tap((file) => {
          this.store.update(({ files }) => ({
            files: arrayRemove(files, file.id, 'fileId')
          }));
        }),
        switchMap((file) => this.sendGroupNotifyMsg(this.query.roomId, CMD.DELETE_FILES, JSON.stringify({ file })))
      )
  }

  //房间文件转码请求 
  fileTransCode = (TransCodeReq: fileTransCodeReq) => {
    return roomService.fileTransCodeSvc(TransCodeReq.roomId, TransCodeReq.id, TransCodeReq.fileUrl)
  }

  //发起文件演示同步
  fileSyn = (filesSynReq: fileSynReq) => {
    return roomService.fileSynSvc(filesSynReq.roomId, filesSynReq.id, filesSynReq.transcodeUrl, filesSynReq.page, filesSynReq.pages)
  }

  //播放回放时拉取文件同步记录
  getFileSyncs = (roomId: string) => {
    return roomService.getFileSyncsSvc(roomId)
  }

  //返回房间信息
  getRoom = (roomId: string) => {
    return roomService.getRoomSvc(roomId)
      .pipe(
        //使用事务
        tap(roomRsp => {
          //把主播流加入到连麦流地址数组的第一位
          this.store.update(state => {
            state.roomId = roomId;
            state.roomName = roomRsp.roomName;
            state.orgId = roomRsp.orgId;
            state.orgName = roomRsp.orgName;
            state.orgLogo = roomRsp.orgLogo;
            state.ownerId = roomRsp.owner;
            state.ownerName = roomRsp.ownerName;
            state.ownerLogo = roomRsp.ownerLogo;
            state.anchorId = roomRsp.anchor;
            state.anchorName = roomRsp.anchorName;
            state.anchorLogo = roomRsp.anchorLogo;
            state.tips = roomRsp.tips;
            state.description = roomRsp.description;
            state.passwd = roomRsp.passwd;
            state.picUrl = roomRsp.picUrl;
            state.preLoadVideo = roomRsp.preLoadVideo;
            state.pauseVideo = roomRsp.pauseVideo;
            state.type = roomRsp.type;
            state.direction = roomRsp.direction;
            state.status = roomRsp.status;
            state.muteStatus = roomRsp.muteStatus;
            state.startTime = new Date(roomRsp.startTime);
            state.endTime = new Date(roomRsp.endTime);
            state.createTime = new Date(roomRsp.createTime);
            state.forceSignIn = roomRsp.forceSignIn;
            state.allowShare = roomRsp.allowShare;
            state.liveStreams = roomRsp.liveStreams;
            state.linkStreams = roomRsp.linkStreams;
            state.files = roomRsp.files;
            state.duration = roomRsp.duration;
            state.visits = roomRsp.visits;
            state.shares = roomRsp.shares;
            state.likes = roomRsp.likes;
            state.signInOptions = roomRsp.signInOptions;
          })
        })
      )
  }

  //创建房间
  createRoom = (params: EditRoomParams) => {
    //如果任意参数为空则不往下执行
    if (
      !params.roomName ||
      !params.description ||
      // !params.direction ||
      // !params.type ||
      !params.startTime ||
      !params.endTime
    ) {
      throw new Error("任意参数不能为空!");
    } else {
      return roomService.createRoomSvc(params);
    }
  }

  //编辑房间
  editRoom = (params: EditRoomParams) => {
    //如果roomId为空则不往下执行
    if (!params.roomId) {
      throw new Error("roomId不能为空!");
    } else {
      return roomService.editRoomSvc(params);
    }
  }

  //获取RoomDetail表完整数据
  getEtcData = (roomId: string) => {
    return roomService.getEtcDataSvc(roomId).pipe(
      tap(etcRes => {
        this.store.update(state => {
          state.duration = etcRes.duration;
          state.visits = etcRes.visits;
          state.shares = etcRes.shares;
          state.likes = etcRes.likes;
        })
      })
    )
  }

  //更新访问数据
  updateEtcData = (roomId: string, params: EtcDataReq) => {
    return roomService.updateEtcDataSvc(roomId, params)
      .pipe(
        tap(etcRes => {
          this.store.update(state => {
            state.duration = etcRes.duration;
            state.visits = etcRes.visits;
            state.shares = etcRes.shares;
            state.likes = etcRes.likes;
          })
        })
      )
  }

  //查询邀请数据
  getInvites = (roomId: string) => {
    return roomService.getInvitesSvc(roomId).
      pipe(
        tap(this.updateInvites)
      );
  }

  //接收邀请成为讲师
  updateInviteAnchor = (roomId: string) => {
    return roomService.inviteAnchorSvc(roomId)
      .pipe(
        tap(this.updateInvites)
      );
  }

  //接受邀请成为助手
  updateInviteAsistant = (roomId: string) => {
    return roomService.inviteAssistantSvc(roomId)
      .pipe(
        tap(this.updateInvites)
      );
  }

  updateInvites = (inviteRes: GetInvitesRsp) => {
    if (inviteRes.anchor && inviteRes.anchor.userId) {
      this.store.update(state => {
        state.anchorId = inviteRes.anchor.userId;
        state.anchorName = inviteRes.anchor.realName;
      });
    }
    if (inviteRes.assistants && inviteRes.assistants.length > 0) {
      console.log("助理返回值", inviteRes);

      this.store.update(state => {
        state.assistants = inviteRes.assistants;
      });
    }
  }

  //FIXME 获得通知消息的订阅，多重订阅导致多次执行
  handleGroupSystemNotify$ = this.notifyMsg$
    .pipe(
      //过滤空指令
      filter(msg => msg && !isObjEmpty(msg)),
      mergeMap(msg => {
        //根据系统提示消息的cmd类型去做相应处理，比如主播发生变化则处理相应本地数据，注意未登录情况下的处理
        switch (msg.cmd) {
          case CMD.OPERATE_CAMERA: { //收到主播操作摄像头(开始，暂停，结束等操作)的通知
            //主播不做处理，并且忽略直播结束后的断流通知
            if (this.query.roomRole === ROOM_ROLE.OWNER_ANCHOR || this.query.roomRole === ROOM_ROLE.ANCHOR || this.query.status === ROOM_STATUS.ENDED) {
              return EMPTY;
            } else {
              // 主播暂停后小主播也要退出连麦
              if (this.query.roomRole === ROOM_ROLE.LINK_ANCHOR) this.quitLink(this.authQuery.userId);

              const status = msg.data as number;
              this.store.update(state => {
                //更新当前房间状态
                state.status = status;
              });

              //继续传递到LiveROom组件层;
              return of(msg);
            }
          }
          //收到邀请主播接受了邀请的通知
          case CMD.ADD_INVITE_ANCHOR: { //收到邀请主播加入的通知
            //TODO 连麦的主播数据暂时不做处理
            const anchor = msg.data as Anchor;

            this.store.update(state => {
              //更新主播信息
              state.anchorId = anchor.userId;
              state.anchorName = anchor.realName;
            });
            return of(msg);
          }
          //收到 移除邀请主播的通知
          case CMD.DEL_INVITE_ANCHOR: { //收到移除邀请主播的通知
            this.store.update(state => {
              //更新主播信息
              state.anchorId = "";
              state.anchorName = "";
            })
            return EMPTY;
          }
          case CMD.ADD_ASSISTANT: { //收到添加助理通知
            const assistant = msg.data as Assistant;

            if (this.authQuery.userId === assistant.userId) {
              return EMPTY;
            } else {
              //FIXME store异步写入，多重订阅可能判断失效
              const exists = this.query.assistants.some(item => item.userId === assistant.userId);
              if (exists) return EMPTY;

              //把新助手写入store
              this.store.update(({ assistants }) => ({
                assistants: arrayAdd(assistants, assistant)
              }))
              return of(msg);
            }
          }
          case CMD.DEL_ASSISTANT: { //收到移除助理通知
            if (this.query.roomRole === ROOM_ROLE.OWNER_ANCHOR || this.query.roomRole === ROOM_ROLE.OWNER_ASSISTANT) {
              return EMPTY;
            } else {
              const assistant = msg.data as Assistant;
              //移除助手
              this.store.update(({ assistants }) => ({
                assistants: arrayRemove(assistants, assistant.userId, "userId")
              }));
              return EMPTY;
            }
          }
          case CMD.VIDEO_BACK: {  //收到视频回放通知
            const data = msg.data;

            //不能直接用原对象，因为是readonly对象； 也不能用Object.assign进行浅拷贝，只能深拷贝对象，不会修改原来的readonly引用对象导致报错
            const copyStream = JSON.parse(JSON.stringify(this.query.liveStreams[0]));
            copyStream.videoUrl = data.videoUrl as string;

            //更新回放地址
            this.store.update(({ liveStreams }) => ({
              liveStreams: arrayUpdate(liveStreams, item => item.streamId === copyStream.streamId, copyStream)
            }))
            return of(msg);
          }
          case CMD.PORN_WARN: {  //收到鉴黄封禁通知
            const warnMsg = msg.data;
            //TODO 可以在liveOprator组件弹窗提示，这里不修改store数据
            return EMPTY;
          }
          case CMD.CHANGE_TIPS: {  //收到修改群提示通知
            const data = msg.data;
            if (data.tips) {
              this.store.update(state => {
                state.tips = data.tips as string;
              })

              return of(msg);
            } else {
              return EMPTY;
            }
          }
          case CMD.FORCE_SIGN_IN: {  //收到签到通知
            const data = msg.data;

            if (data.hasSignInContent) {
              if (data.forceSignIn) {
                this.store.update(state => {
                  state.forceSignIn = data.forceSignIn;
                })
              } else {
                this.store.update(state => {
                  state.forceSignIn = false;
                })
              }
            } else {
              this.store.update(state => {
                state.forceSignIn = false;
              })
            }
            return of(msg);
          }
          case CMD.ALLOW_SHARE: {  //分享改变
            const data = msg.data;
            if (data.allowShare) {
              this.store.update(state => {
                state.allowShare = true;
              })
            } else {
              this.store.update(state => {
                state.allowShare = false;
              })
            }
            return EMPTY;
          }
          case CMD.TRANSCODE_FILES: {  //收到文件转码成功通知
            const file = msg.data.file as File;

            this.store.update(({ files }) => ({
              files: arrayUpdate(files, item => item.id === file.id, file)
            }));
            return of(msg);
          }
          case CMD.UPLOAD_FILES: {  //收到文件上传通知
            const file = msg.data.file as File;

            //FIXME store异步写入，多重订阅可能判断失效
            const exists = this.query.files.some(item => item.id === file.id);
            if (exists) return EMPTY;

            this.store.update(({ files }) => ({
              files: arrayAdd(files, file)
            }));
            return EMPTY;
          }
          case CMD.DELETE_FILES: {  //收到文件删除通知
            const file = msg.data.file as File;

            this.store.update(({ files }) => ({
              files: arrayRemove(files, file.id, 'id')
            }));
            return EMPTY;
          }
          case CMD.NOTIFY_ANCHOR_CHANGE: {
            //连麦主播发生变化
            if (this.query.roomRole === ROOM_ROLE.OWNER_ANCHOR || this.query.roomRole === ROOM_ROLE.OWNER_ASSISTANT ||
              this.query.roomRole === ROOM_ROLE.ANCHOR || this.query.roomRole === ROOM_ROLE.ASSISTANT || this.query.roomRole === ROOM_ROLE.LINK_ANCHOR) {

              return this.getLinkStreams(this.query.roomId)
                .pipe(
                  tap(linkStreams => {
                    // console.log('群发，踢出直播间显示这一段, linkStreams', linkStreams);
                    linkStreams.map(item => {
                      if (item.status === ROOM_STATUS.ENDED) {
                        this.judgeRole()
                      }
                    })
                    if (this.query.roomRole === ROOM_ROLE.OWNER_ANCHOR || this.query.roomRole === ROOM_ROLE.ANCHOR) {
                      if (linkStreams.length > 0) {
                        this.store.update(state => {
                          state.ui.mode = LIVE_MODE.RTC as HDLevel;
                        });
                      } else {
                        this.store.update(state => {
                          state.ui.mode = LIVE_MODE.HD as HDLevel;
                        });
                      }
                    }
                  })
                )
            }
            return EMPTY;
          }
          case CMD.KICK_ANCHOR: {
            Taro.showToast({
              title: '已断开',
              icon: 'none',
              duration: 2000,
            })
            return EMPTY;
          }
          default:
            //其他放行返回页面层做处理
            return of(msg);
        }
      })
    )

  //开始直播，暂停直播，结束直播的操作
  operateCamera = (operation: string) => {
    const roomId = this.query.roomId;

    return roomService.operateCameraSvc(roomId, operation)
      .pipe(
        switchMap(() => {
          let status = ROOM_STATUS.NOT_STARTED;
          switch (operation) {
            case LIVE_OPERATION.START:
              status = ROOM_STATUS.STARTED;
              break;
            case LIVE_OPERATION.PAUSE:
              status = ROOM_STATUS.PAUSED;
              break;
            case LIVE_OPERATION.RESUME:
              status = ROOM_STATUS.STARTED;
              break;
            case LIVE_OPERATION.STOP:
              status = ROOM_STATUS.ENDED;
              break;
            default:
              break;
          }
          this.store.update(state => {
            //更新连麦流
            state.status = status;
          })

          //开始直播的通知已经由live pusher的事件发起，其余操作的通知这里发
          return this.sendGroupNotifyMsg(this.query.roomId, CMD.OPERATE_CAMERA, status.toString())
            .pipe(
              map(() => 1)
            )
          // if (this.query.type === LIVE_TYPE.TEXT) {
          //   console.log('视频直播是否有打印');

          //   return this.sendGroupNotifyMsg(this.query.roomId, CMD.OPERATE_CAMERA, status.toString())
          //     .pipe(
          //       map(() => 1)
          //     )
          // } else {
          //   return of(1);
          // }
        })
      )
  }

  saveRoomStat = (roomId: string, type: number) => {
    const data = {
      type
    } as RoomStatReq;

    return roomService.saveRoomStatSvc(roomId, data);
  }

  //心跳更新并返回最新数据，用于更新房间状态
  updateTS = (roomId: string) => {
    return this.authQuery.userId$
      .pipe(
        //未登录用户的userId传"none"
        switchMap(uid => roomService.updateTSSvc(roomId, uid || "none")),
        tap(etcRes => {
          this.store.update(state => {
            state.duration = etcRes.duration;
            state.visits = etcRes.visits;
            state.shares = etcRes.shares;
            state.likes = etcRes.likes;
          })
        })
      )
  }

  //首页信息
  getMain = () => {
    return roomService.getHomePageSvc()
  }

  //FIXME 签到设置,如何取消已有签到内容并群发通知？
  signInSetting = (roomId: string, data: SignInSettingReq) => {
    // 通过判断数组是否有必填项，确定是否有开启签到
    // const judgeArr = data.filter((item) => {
    //   if (item.required === true) {
    //     return item
    //   }
    // })
    // console.log('筛选数组，筛选必选项111', judgeArr);
    // this.store.update(state => {
    //   if (judgeArr && judgeArr.length > 0) {
    //     state.openSignIn = true
    //   } else {
    //     state.openSignIn = false
    //   }
    // })

    let paramObj = {}

    if (data.signInOptions && data.signInOptions.length > 0) {
      paramObj = { hasSignInContent: true };
      if (data.forceSign) {
        paramObj = { hasSignInContent: true, forceSignIn: true }
      } else {
        paramObj = { hasSignInContent: true, forceSignIn: false }
      }
    } else {
      paramObj = { hasSignInContent: false, forceSignIn: false };
    }

    return roomService.signInSettingSvc(roomId, data)
      .pipe(
        //群发通知有签到内容可以填写(触发按钮显示/隐藏)
        switchMap(() => this.sendGroupNotifyMsg(roomId || this.query.roomId, CMD.FORCE_SIGN_IN, JSON.stringify(paramObj))),
      )
  }

  // 获取签到信息
  getSignInFrom = () => {
    return roomService.getSignInFromSvc(this.query.roomId)
  }

  // 获取用户签到信息
  getUserSignInfo = (roomId: string) => {
    return roomService.getUserSignInfoSvc(roomId)
  }

  //用户签到
  UserSignIn = (roomId: string, data: SignInContentReq[]) => {
    return roomService.getUserSignInSvc(roomId, data)
  }

  //修改直播间密码
  editRoomPwd = (data: EditRoomParams) => {
    //如果任意参数为空则不往下执行
    if (
      // !data.passwd || !data.roomId , 清空密码时需要传空 '' 
      !data.roomId
    ) {
      throw new Error("任意参数不能为空!");
    } else {

      return roomService.editRoomPwdSvc(data)
        .pipe(
          tap(() => {
            this.store.update(state => {
              state.passwd = data.passwd as string
            })
          })
        )
    }
  }

  //编辑修改直播间评论设置状态 
  editRoomChat = (params: EditRoomParams) => {
    //传入roomId
    params.roomId = this.query.roomId;
    return roomService.editRoomSvc(params)
      .pipe(
        tap(res => {
          this.store.update(state => {
            state.muteStatus = params.muteStatus || MUTE_STATUS.NORMAL;
          });
        })
      )

  }

  //编辑修改直播间公告 
  editRoomTips = (params: EditRoomParams) => {
    //传入roomId
    return roomService.editRoomSvc(params)
      .pipe(
        //群发通知修改后的公告
        switchMap(() => this.sendGroupNotifyMsg(params.roomId || this.query.roomId, CMD.CHANGE_TIPS, JSON.stringify({ tips: params.tips || "" })))
      )
  }

  //主播文件演示结束通知
  syncEnded = (roomId) => {
    return this.sendGroupNotifyMsg(roomId, CMD.SYNC_ENDED)
  }

  //修改强制签到
  editForceSign = (data: EditRoomParams) => {
    if (!data.roomId) {
      throw new Error("roomId参数不能为空!");
    } else {
      return roomService.editRoomSvc(data)
        .pipe(
          //群发通知有强制签到
          switchMap(() => this.sendGroupNotifyMsg(data.roomId || this.query.roomId, CMD.FORCE_SIGN_IN, JSON.stringify({ forceSignIn: data.forceSignIn as boolean })))
        )
    }
  }

  // 修改分享状态
  editAllowShare = (data: EditRoomParams) => {
    if (!data.roomId) {
      throw new Error("roomId参数不能为空!");
    } else {
      return roomService.editRoomSvc(data)
        .pipe(
          //群发通知有允许分享
          switchMap(() => this.sendGroupNotifyMsg(data.roomId || this.query.roomId, CMD.ALLOW_SHARE, JSON.stringify({ allowShare: data.allowShare as boolean }))),
          tap(() => {
            this.store.update(state => {
              state.allowShare = data.allowShare as boolean
            })
          })
        )
    }
  }

  // 获取用户分享榜refId
  getRefId = (roomId: string) => {
    return roomService.getRefIdSvc(roomId)
  }

  // 根据refId获取roomId
  getRoomByRef = (refId: string) => {
    return roomService.getRoomByRefSvc(refId)
  }

  // 获取用户分享榜信息
  getRefRanking = (roomId: string) => {
    return roomService.getRefRankingSvc(roomId)
  }

  // 获取连麦列表
  getSearchList = (roomId: string, pageNum: number, pageSize: number, searchKey: string) => {
    return roomService.getSearchListSvc(roomId, pageNum, pageSize, searchKey)
  }
  // 小主播接受连麦邀请
  accessAudienceInvite = (roomId: string) => {
    return roomService.accessAudienceInviteSvc(roomId)
      .pipe(
        switchMap(() => this.getLinkStreams(roomId)),
        tap(() => {
          this.store.update(state => {
            state.roomRole = ROOM_ROLE.LINK_ANCHOR;
          })
        })
      )
  }

  //群发通知
  sendGroupNotifyMsg = (roomId: string, opType: string, data?: string) => {
    return messageService.sendGroupNotifyMsgSvc(roomId, opType, data);
  }
}

export const makeFacade = (): RoomFacade => {
  const [store, query] = makeStore();
  const [, authQuery] = makeAuthStore();
  const [, msgQuery] = makeMsgStore();

  return new RoomFacade(store, query, authQuery, msgQuery);
}
